#include "../tps/tps.h"
#include "../tps/tps_xml_serializer.h"
#include "../tps/tps_remote_method.h"

#include <iostream>

struct IFace
{
	virtual ~IFace()
	{
	}
	virtual void Mtd1() = 0;
	virtual char const* Mtd2() const = 0;
	virtual bool Mtd3(int) = 0;
	virtual bool Mtd4(int) const = 0;
	virtual int Mtd5(char const *, bool, double, long, char) const = 0;
	virtual long Mtd6(int const *, bool const &, double &, long *, char) const = 0;
	virtual void Mtd7(wchar_t const *) = 0;
};

TPS_BEGIN_MAP(IFace)
	TPS_METHOD(Mtd1)
	TPS_METHOD(Mtd2)
	TPS_METHOD(Mtd3)
	TPS_METHOD(Mtd4)
	TPS_METHOD(Mtd5)
	TPS_METHOD(Mtd6)
	TPS_METHOD(Mtd7)
TPS_END_MAP()

class IFaceImpl
	: public IFace
{
public:
	virtual void Mtd1()
	{
		std::cout << __FUNCTION__ << std::endl;
	}
	virtual char const* Mtd2() const
	{
		std::cout << __FUNCTION__ << std::endl;
        return "Ret value from Mtd2";
	}
	virtual bool Mtd3(int p1)
	{
		std::cout << __FUNCTION__ << std::endl;
		std::cout << "p1 = " << p1 << std::endl;
		return false;
	}
	virtual bool Mtd4(int p1) const
	{
		std::cout << __FUNCTION__ << std::endl;
		std::cout << "p1 = " << p1 << std::endl;
		return true;
	}
	virtual int Mtd5(char const *p1, bool p2, double p3, long p4, char p5) const
	{
		std::cout << __FUNCTION__ << std::endl;
		std::cout
			<< "p1 = " << p1 << std::endl
			<< "p2 = " << std::boolalpha << p2 << std::endl
			<< "p3 = " << p3 << std::endl
			<< "p4 = " << p4 << std::endl
			<< "p5 = " << p5 << std::endl;
		return 5;
	}
	virtual long Mtd6(int const *p1, bool const &p2, double &p3, long *p4, char p5) const
	{
		std::cout << __FUNCTION__ << std::endl;
		std::cout
			<< "p1 = " << *p1 << std::endl
			<< "p2 = " << std::boolalpha << p2 << std::endl
			<< "p3 = " << p3 << std::endl
			<< "p4 = " << *p4 << std::endl
			<< "p5 = " << p5 << std::endl;
		*p4 = 11111;
		p3 = 3.14;
		return 10;
	}
	virtual void Mtd7(wchar_t const *p1) 
	{
		std::cout << __FUNCTION__ << std::endl;
		std::wcout << L"p1 = " << p1 << std::endl;
	}
};

class Transport;

typedef Tps::RemoteMethod<Tps::XmlSerializer, Tps::XmlDeserializer, Transport> RemoteMethod;

typedef IFacePS::Stub<RemoteMethod> IFaceStub;

class Transport
{
public:
	std::auto_ptr<std::vector<char> > SendRequest(void const *buffer, unsigned long bufferLen)
	{
		return Stub->CallMethod(buffer, bufferLen);
	}
	void SetStub(std::auto_ptr<IFaceStub> stub)
	{
		Stub = stub;
	}

private:
	std::auto_ptr<IFaceStub> Stub;
};

int main()
{
	try
	{
		Transport tr;
		RemoteMethod rm(&tr);
		IFaceImpl Impl;
		tr.SetStub(std::auto_ptr<IFaceStub>(new IFaceStub(&Impl, &rm)));
		
		IFacePS::Proxy<RemoteMethod> p(&rm, 159, 753);

		std::cout << "Call Mtd1" << std::endl;
		p.Mtd1();
		std::cout << std::endl;

		std::cout << "Call Mtd2" << std::endl;
		std::cout << "Mtd2 ret: " << p.Mtd2() << std::endl;
		std::cout << std::endl;

		std::cout << "Call Mtd3" << std::endl;
		std::cout << "Mtd3 ret: " << (p.Mtd3(1) ? "true" : "false") << std::endl;
		std::cout << std::endl;

		std::cout << "Call Mtd4" << std::endl;
		std::cout << "Mtd4 ret: " << (p.Mtd4(1) ? "true" : "false") << std::endl;
		std::cout << std::endl;

		std::cout << "Call Mtd5" << std::endl;
		std::cout << "Mtd5 ret: " << p.Mtd5("String", true, 1.1, 1, 'x') << std::endl;
		std::cout << std::endl;

		int IntValue = 1;
		double DoubleValue = 1.1;
		long LongValue = 1;
		std::cout << "Out params before call Mtd6: " << DoubleValue << "\t" << LongValue << std::endl;
		std::cout << "Call Mtd6" << std::endl;
        long RetMtd6 = p.Mtd6(&IntValue, true, DoubleValue, &LongValue, 'x');
		std::cout << "Mtd6 ret: " << RetMtd6 << std::endl;
		std::cout << "Out params after call Mtd6: " << DoubleValue << "\t" << LongValue << std::endl;
		std::cout << std::endl;

		std::cout << "Call Mtd7" << std::endl;
		p.Mtd7(L"String");
		std::cout << std::endl;
	}
	catch (std::exception const &e)
	{
		std::cerr << e.what() << std::endl;
	}
	return 0;
}
